package com.zjx.activiti.controller;

import com.zjx.activiti.common.Result;
import com.zjx.activiti.service.RuntimeInfoService;
import com.zjx.activiti.vo.RuExecution;
import com.zjx.activiti.vo.RuTask;
import com.zjx.activiti.util.ToWeb;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;

import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 运行中的流程
 *
 * @Auther: zhaojx
 * @Date: 2021/8/25 15:04
 */
@Slf4j
@RestController
@RequestMapping("runs")
public class RunningProcessController {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RuntimeInfoService runtimeInfoService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 挂起、激活流程实例 （挂起、激活单个流程实例）
     */
    @RequestMapping(value = "update/{state}/{processInstanceId}")
    public Object updateState(@PathVariable("state") String state, @PathVariable("processInstanceId") String processInstanceId) {
        if (state.equals("active")) {
            runtimeService.activateProcessInstanceById(processInstanceId);
            System.out.println("已激活ID为[" + processInstanceId + "]的流程实例。");
        } else if (state.equals("suspend")) {
            runtimeService.suspendProcessInstanceById(processInstanceId);
            System.out.println("已挂起ID为[" + processInstanceId + "]的流程实例。");
        }
        return ToWeb.buildResult().refresh();
    }

    /**
     * 获取任务列表
     *
     * @param rowSize
     * @param page
     * @return
     */
    @GetMapping(value = "tasks")
    public Object tasks(@RequestParam(value = "rowSize", defaultValue = "1000", required = false) Integer rowSize,
                        @RequestParam(value = "page", defaultValue = "1", required = false) Integer page) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        List<Task> tasks = taskQuery.listPage(rowSize * (page - 1), rowSize);
        long count = taskQuery.count();
        List<RuTask> list = new ArrayList<>();
        for (Task task : tasks) {
            list.add(new RuTask(task));
        }
        return ToWeb.buildResult().setRows(
                ToWeb.Rows.buildRows()
                        .setRowSize(rowSize)
                        .setTotalPages((int) (count / rowSize + 1))
                        .setTotalRows(count)
                        .setList(list)
                        .setCurrent(page)
        );
    }


    /**
     * 查询当前用户角色对应的任务
     *
     * @return
     */
    @RequestMapping(value = "tasks/role")
    public Object tasksByRoleList(String processDefinitionKey) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        // 1. 查询登录人所在角色，在根据角色进行查询 ,获取角色列表
        List<String> roleList = null; //实际上根据用户ID查询当前用户具有的角色
        List<Task> resultList = new ArrayList<>();
        for (String role : roleList) {
            // 任务列表
            List<Task> list = taskQuery.processDefinitionKey(processDefinitionKey)
                    .taskAssignee(role)
                    .list();// 组任务的办理人查询
            resultList.addAll(list);

            for (Task task : list) {
                log.info("任务处理人【{}】", task.getAssignee());
                log.info("流程名称【{}】", task.getName());
                log.info("任务id【{}】", task.getId());
                log.info("流程定义id【{}】", task.getProcessDefinitionId());
                log.info("执行对象id【{}】", task.getExecutionId());
            }

        }
        return ToWeb.buildResult().setRows(
                ToWeb.Rows.buildRows()
                        .setRowSize(resultList.size())
                        .setList(resultList)
        );
    }


    /**
     * 获取运行中的节点列表
     *
     * @param rowSize 一页数据大小
     * @param page    当前页码
     * @return
     */
    @GetMapping
    public Object getList(@RequestParam(value = "rowSize", defaultValue = "1000", required = false) Integer rowSize,
                          @RequestParam(value = "page", defaultValue = "1", required = false) Integer page) {
        List<Execution> executions = runtimeService.createExecutionQuery().listPage(rowSize * (page - 1), rowSize);
        long count = runtimeService.createExecutionQuery().count();
        List<RuExecution> list = new ArrayList<>();
        for (Execution execution : executions) {
            list.add(new RuExecution(execution));
        }
        return ToWeb.buildResult().setRows(
                ToWeb.Rows.buildRows()
                        .setRowSize(rowSize)
                        .setTotalPages((int) (count / rowSize + 1))
                        .setTotalRows(count)
                        .setList(list)
                        .setCurrent(page)
        );
    }

    /**
     * 我的待办任务(根据审批人和流程定义key进行查询)
     *
     * @param userId
     * @return
     */
    @GetMapping(value = "/tasks/ing")
    public Result<List<RuTask>> myTasks(@RequestParam("userId") String userId,
                                        @RequestParam(value = "processDefinitionKey", required = false) String processDefinitionKey) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        taskQuery.taskCandidateOrAssigned(userId);
        if (StringUtils.hasLength(processDefinitionKey)) {
            taskQuery.processDefinitionKey(processDefinitionKey);
        }
        List<RuTask> actRuTasks = new ArrayList<>();
        for (Task task : taskQuery.list()) {
            actRuTasks.add(new RuTask(task));
        }
        return new Result<>(actRuTasks);
    }

    /**
     * 完成任务
     * <p>
     * 这两个是本节点的业务数据---增加到所有节点
     * dealReason: 处理原因
     * dealType: 处理类型
     * <p>
     * 注意顺序，先给值，后完成。
     * <p>
     * dealType 0 审核通过 1 驳回
     *
     * @param taskId
     * @return
     */
    @PostMapping(value = "tasks/do/{taskId}")
    public Object tasks(@PathVariable String taskId, @RequestBody Map<String, Object> params) {
        String dealUserId = params.get("dealUserId").toString();
        String dealType = (String) params.get("dealType");
        String dealReason = (String) params.get("dealReason");
        //驳回的节点key
        String rejectElemKey = Objects.isNull(params.get("rejectElemKey")) ? "" : params.get("rejectElemKey").toString();

        //        查询任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateOrAssigned(dealUserId)
                .singleResult();
        if (Objects.isNull(task)) {
            return false;
        }
        //如果任务的代理人为空则需要拾取任务
        if (!StringUtils.hasLength(task.getAssignee())) {
            taskService.claim(taskId, dealUserId);
        }

        boolean taskDo = true;
        if (null == params || params.isEmpty()) {
            taskService.complete(taskId);
            return taskDo;
        }

        //驳回
        if ("1".equals(dealType)) {
            //获取驳回节点定义key
            try {
                //设置流程变量
                taskService.setVariableLocal(taskId, "dealUserId", dealUserId);
                taskService.setVariableLocal(taskId, "dealUnitId", dealUserId);
                taskService.setVariable(taskId, "dealType", dealType);
                taskService.setVariable(taskId, "dealReason", dealReason);

                taskDo = runtimeInfoService.rejected(taskId, rejectElemKey, dealReason);
            } catch (Exception e) {
                taskDo = false;
                log.error("驳回处理异常：{}", e);
            }
            //通过
        } else if ("0".equals(dealType)) {
            completeTasks(taskId, params);
        }
        return taskDo;
    }

    /**
     * 查询可以驳回的节点
     *
     * @param procinstid
     * @return
     */
    @PostMapping(value = "nodes/{procinstid}")
    public Object tasks(@PathVariable String procinstid) {
        // 获取流程历史中已执行节点，并按照节点在流程中执行先后顺序排序
        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procinstid)
                .activityType("userTask")   //用户任务
                .finished()       //已经执行的任务节点
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();
        List<Map<String, String>> list = new ArrayList<>();
        // 已执行的节点ID集合
        if (!Objects.isNull(historicActivityInstanceList) && historicActivityInstanceList.size() > 0) {
            Map<String, String> map = new LinkedHashMap<String, String>();
            for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
                if (!map.containsKey(historicActivityInstance.getActivityId())) {
                    map.put("activityId", historicActivityInstance.getActivityId());
                    map.put("activityName", historicActivityInstance.getActivityName());
                    list.add(map);
                }
            }
        }
        return list;
    }

    /**
     * 驳回任务实现方式二(驳回到上一步)
     *
     * @param taskId
     * @param params
     * @return
     */
    @PostMapping(value = "tasks/reject/{taskId}")
    public Object reject2(@PathVariable String taskId, @RequestBody Map<String, Object> params) {
        try {
            Map<String, Object> variables;
            // 取得当前任务
            HistoricTaskInstance currTask = historyService.createHistoricTaskInstanceQuery().taskId(taskId)
                    .singleResult();
            // 取得流程实例
            ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(currTask.getProcessInstanceId()).singleResult();
            if (instance == null) {
                // 流程已经结束
            }
            variables = instance.getProcessVariables();
            // 取得流程定义
            ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                    .getDeployedProcessDefinition(currTask.getProcessDefinitionId());
            if (definition == null) {
                // 流程定义未找到
            }
            // 取得上一步活动
            ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
                    .findActivity(currTask.getTaskDefinitionKey());
            List<PvmTransition> nextTransitionList = currActivity.getIncomingTransitions();
            // 清除当前活动的出口
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            List<PvmTransition> pvmTransitionList = currActivity.getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();

            // 建立新出口
            List<TransitionImpl> newTransitions = new ArrayList<TransitionImpl>();
            for (PvmTransition nextTransition : nextTransitionList) {
                PvmActivity nextActivity = nextTransition.getSource();
                ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) definition).findActivity(nextActivity.getId());
                TransitionImpl newTransition = currActivity.createOutgoingTransition();
                newTransition.setDestination(nextActivityImpl);
                newTransitions.add(newTransition);
            }
            // 完成任务
            List<Task> tasks = taskService.createTaskQuery().processInstanceId(instance.getId())
                    .taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
            for (Task task : tasks) {
                taskService.complete(task.getId(), variables);
                historyService.deleteHistoricTaskInstance(task.getId());
            }
            // 恢复方向
            for (TransitionImpl transitionImpl : newTransitions) {
                currActivity.getOutgoingTransitions().remove(transitionImpl);
            }
            for (PvmTransition pvmTransition : oriPvmTransitionList) {
                pvmTransitionList.add(pvmTransition);
            }

            // 成功
            log.info("驳回成功");
        } catch (Exception e) {
            // 异常
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 签收任务
     *
     * @param taskId
     * @param userId
     * @return
     */
    @PostMapping(value = "tasks/claim/{taskId}")
    public Object claim(@PathVariable String taskId, @RequestParam String userId) {
        boolean taskDo = true;
        if (StringUtils.isEmpty(taskId) || StringUtils.isEmpty(userId)) {
            throw new RuntimeException("参数错误");
        }
        //        查询任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(userId)
                .singleResult();
        if (task != null) {
//            拾取任务
            taskService.claim(taskId, userId);
            log.info("任务 taskid={} 被用户:{} 拾取完成", taskId, userId);
        }
        return taskDo;
    }

    /**
     * 取回签收任务
     *
     * @param taskId
     * @param userId
     * @return
     */
    @PostMapping(value = "tasks/unclaim/{taskId}")
    public Object unclaim(@PathVariable String taskId, @RequestParam String userId) {
        boolean taskDo = true;
        if (StringUtils.isEmpty(taskId) || StringUtils.isEmpty(userId)) {
            throw new RuntimeException("参数错误");
        }
        //        查询任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(userId)
                .singleResult();
        if (task != null) {
//            拾取任务
            taskService.unclaim(taskId);
            log.info("任务 taskid={} 被用户:{} 放弃签收", taskId, userId);
        }
        return taskDo;
    }

    /**
     * 委派任务
     *
     * @param taskId
     * @return
     */
    @PostMapping(value = "delegate/{taskId}")
    public Object delegateTask(@PathVariable String taskId) {
        taskService.delegateTask(taskId, "zhangsan");
        return true;
    }

    /**
     * 委派人完成任务
     *
     * @param taskId
     * @return
     */
    @PostMapping(value = "resolve/{taskId}")
    public Object resolveTask(@PathVariable String taskId, @RequestBody Map<String, Object> map) {
        taskService.resolveTask(taskId, map);
        return true;
    }


    /**
     * 根据任务拥有者查询任务
     *
     * @param processDefinitionKey
     * @return
     */
    @PostMapping(value = "getTaskByOwner/{processDefinitionKey}")
    public Result<List<RuTask>> getTaskByOwner(@PathVariable String processDefinitionKey, @RequestParam String
            assignee) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        // 任务列表
        List<Task> list = taskQuery.processDefinitionKey(processDefinitionKey).taskOwner(assignee).list();// 指定任务拥有者
        List<RuTask> actRuTasks = new ArrayList<>();
        for (Task task : list) {
            actRuTasks.add(new RuTask(task));
        }
        return new Result<>(actRuTasks);
    }

    /**
     * 指定任务办理人
     *
     * @param taskId
     * @return
     */
    @PostMapping(value = "trunTask/{taskId}")
    public Object trunTask(@PathVariable String taskId, @RequestParam String assignee) {
        taskService.setAssignee(taskId, assignee);
        return true;
    }

    /**
     * 终止流程
     *
     * @param taskId  任务ID
     * @param opinion 审批意见
     * @return
     */
    @PostMapping(value = "end/{taskId}")
    public void endTask(@PathVariable String taskId, @RequestParam String opinion) {

        //根据taskID查询任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        //获取结束节点
        ActivityImpl endActivity = runtimeInfoService.findActivitiImpl(taskId, "end");

        if (endActivity == null) {
            return;
        }

        Map<String, Object> variables = new HashMap<String, Object>();
        if (!StringUtils.isEmpty(opinion)) {  //审核意见
            variables.put("驳回意见", opinion);
        }
        // 跳转节点为空，默认提交操作
        if (StringUtils.isEmpty(endActivity.getId())) {

            if (!StringUtils.isEmpty(task.getOwner())) {
                // 被委派人处理完成任务
                taskService.resolveTask(task.getId(), variables);
            }
            taskService.complete(taskId, variables);
        } else {// 流程转向操作
            //turnTransition(taskId, activityId, variables);
            // 当前节点
            ActivityImpl currActivity = runtimeInfoService.findActivitiImpl(taskId, null);

            // 清空当前流向
            // 存储当前节点所有流向临时变量
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            // 获取当前节点所有流向，存储到临时变量，然后清空
            List<PvmTransition> pvmTransitionList = currActivity
                    .getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();

            // 创建新流向
            TransitionImpl newTransition = currActivity.createOutgoingTransition();
            // 目标节点
            ActivityImpl pointActivity = runtimeInfoService.findActivitiImpl(taskId, endActivity.getId());
            // 设置新流向的目标节点
            newTransition.setDestination(pointActivity);

            if (!StringUtils.isEmpty(task.getOwner())) {
                // 被委派人处理完成任务
                taskService.resolveTask(task.getId(), variables);
            }
            // 执行转向任务
            taskService.complete(taskId, variables);
            // 删除目标节点新流入
            pointActivity.getIncomingTransitions().remove(newTransition);

            // 还原以前流向
            //restoreTransition(currActivity, oriPvmTransitionList);
            // 清空现有流向
            List<PvmTransition> pvmTransitionListC = currActivity.getOutgoingTransitions();
            pvmTransitionListC.clear();
            // 还原以前流向
            for (PvmTransition pvmTransition : oriPvmTransitionList) {
                pvmTransitionListC.add(pvmTransition);
            }
        }

    }

    /**
     * 根据任务ID查询当前业务数据（流程变量数据）
     *
     * @param taskId
     * @return
     */
    @GetMapping(value = "/tasks/buss")
    public Object bussNow(@RequestParam("taskId") String taskId) {
        Map<String, Object> variables = taskService.getVariables(taskId);
        return variables;
    }


    /**
     * 根据实例ID删除流程
     *
     * @param id
     * @return
     */
    @DeleteMapping("{id}")
    public Object deleteOne(@PathVariable("id") String id) {
        //根据deploymentID删除定义的流程，普通删除
        runtimeService.deleteProcessInstance(id, "deleteby applicant");
        System.out.println("普通删除--流程定义删除成功");
        return ToWeb.buildResult().refresh();
        //级联删除
//        repositoryService.deleteDeployment(id, true);
//        System.out.println("强制删除--流程定义删除成功");
    }


    private void completeTasks(@PathVariable String taskId, @RequestBody Map<String, Object> params) {
        log.info("完成任务参数：taskId={} ,params={}", taskId, params);
        Map<String, Object> variables = new HashMap<>();
        variables.put("dealUserId", params.get("dealUserId"));
        variables.put("dealUnitId", params.get("dealUnitId"));
        taskService.setVariablesLocal(taskId, variables);
        variables = new HashMap<>();
        variables.put("dealType", params.get("dealType"));
        variables.put("dealReason", params.get("dealReason"));
        taskService.complete(taskId, variables);
        log.info("完成任务：任务ID：" + taskId);
    }


}
